home *** CD-ROM | disk | FTP | other *** search
/ Your Choice 1 / your choice.zip / your choice / PRGMMING / VISIONIX / VAVTIOU.PAS < prev    next >
Pascal/Delphi Source File  |  1993-12-28  |  31KB  |  1,100 lines

  1. {
  2.  ════════════════════════════════════════════════════════════════════════════
  3.  
  4.  Visionix Avatar In/Out Driver Unit (VAvtIOu)
  5.    Version 0.2
  6.  Copyright 1991,92,93 Visionix
  7.  ALL RIGHTS RESERVED
  8.  
  9.  ────────────────────────────────────────────────────────────────────────────
  10.  
  11.  ** revision history in reverse chronological order **
  12.  
  13.  Initials  Date      Comment
  14.  ────────  ────────  ────────────────────────────────────────────────────────
  15.  
  16.  jrt       12/23/93  Added documentation.
  17.  
  18.  jrt       11/15/93  Finished out filter.
  19.  
  20.  ────────────────────────────────────────────────────────────────────────────
  21.  
  22.  C A V E A T S   /  K N O W N   B U G S
  23.  
  24.    - on the scroll, ra/quick say to scroll the area
  25.      1,7,80,25 by one line.  we need to validate that the area
  26.      we are told to scroll is within the current window.
  27.  
  28. }
  29.  
  30.  
  31. (*-
  32.  
  33. [SECTION: Section 2: The Text I/O Libraries]
  34. [CHAPTER: Chapter 2: The Avatar Driver & Filter I/O Unit]
  35.  
  36. [TEXT]
  37.  
  38. <Overview>
  39.  
  40. NOTE!  This BETA does not include the AVATAR driver procedure.
  41. It will be included in the next BETA!
  42.  
  43. The VAVTiou unit contains only two procedures:  AvatarFilter and
  44. AvatarOutDriverProc.  As the names imply, AvatarFilter is a VOUT filter
  45. for Avatar 0+ commands, and AvatarOutDriverProc is an VOUT output driver
  46. for Avatar.
  47.  
  48. For more information on text filters, drivers, sub-channels, etc., be sure
  49. to read the VOUTu and VINu chapters.
  50.  
  51.  
  52. <<The AvatarFilter>>
  53.  
  54.   The Avatar Filter is a VOUT filter procedure.  AvatarFilter can be
  55.   attached to a VOUT sub-channel via a call to VOutFilterAttach.
  56.   After the AvatarFilter has been attached, it will "filter" all of the
  57.   Avatar commands in the text-stream sent to that channel, and convert
  58.   the Avatar commands one or more "out driver packets", which is the
  59.   internal command format used by VOUT.
  60.  
  61.   <<<What the heck does this mean?>>>
  62.  
  63.   Basically it means that after you attach the Avatarfilter to a
  64.   sub-channel, you can write Avatar commands into that sub-channel, and
  65.   the Avatar commands will be properly interpreted and executed on the
  66.   sub-channels display.  For example, if you were to attach the Avatar
  67.   filter to the sub-channel used by VCRTu, you could then use
  68.   Avatar commands in your WRITE and WRITELN statements, and the appropriate
  69.   colors, text, actions, etc would appear on your monitor.
  70.  
  71.   <<<Examples and usage>>>
  72.  
  73.   To attach the Avatar filter to the VCRTU's output sub-channel (which is
  74.   created automatically in the VCRTu units init-code):
  75.  
  76.   VOutFilterAttach( CrtOCH,
  77.                     0,
  78.                     'AvatarFILTER',
  79.                     'Bx00VMEM',
  80.                     AvatarFilter,
  81.                     0,0,0            );
  82.  
  83.  
  84.     CrtOCH is the channel handle for VCRTus output-channel.
  85.     As a paramater to VOutFilterAttach, it tells VOUT which channel
  86.     to attach the filter to.
  87.  
  88.     The second parameter, 0, is the flags parameter.  AvatarFilter
  89.     currently has no flags.
  90.  
  91.     The third parameter, 'AvatarFILTER', is the name by which this
  92.     instance of the filter is managed.
  93.  
  94.     The fourth parameter, 'Bx00VMEM', is the name of the sub-channel
  95.     off of the "CrtOCH" channel to which the filter should be
  96.     attached.  'Bx00VMEM' is the name that VCRTu uses for the default
  97.     sub-channel it creates which goes to the primary displays
  98.     video memory.
  99.  
  100.     The fifth parameter, AvatarFilter, is the filter procedure to
  101.     attach.  Since we are attaching the Avatar filter, we specify
  102.     the procedure AvatarFilter.
  103.  
  104.     The last three parameters to VOutFilterAttach are parameters/values
  105.     which are passed to the AvatarFilter.  Currently AvatarFilter has
  106.     no parameters, so we leave them all set to 0.
  107.  
  108.   To attach an Avatar filter to a new sub-channel, which happens to use
  109.   the Avatar Driver:
  110.  
  111.     { first we create a new-sub channel off of the CRT output channel }
  112.     { this new-sub channel will use the Avatar output driver procedure. }
  113.     { note that the AvatarOutDriverProc is very different from the      }
  114.     { Avatar filter.  We'll explain shortly...                          }
  115.  
  116.     { part 1 }
  117.  
  118.     VOutSubChannelNew( CrtOCH,
  119.                        0,
  120.                        'AvatarOUT',
  121.                        AvatarOutDriverProc,
  122.                        caoDOS,0,0                     );
  123.  
  124.  
  125.     { Then we attach the Avatar filter to the new sub-channel }
  126.  
  127.     { part 2 }
  128.  
  129.  
  130.     VOutFilterAttach( CrtOCH,
  131.                       0,
  132.                       'AvatarFILTER',
  133.                       'AvatarOUT',  {<--note we specify the new sub-chan name}
  134.                       AvatarFilter,
  135.                       0,0,0            );
  136.  
  137.     In "Part 1" of this example we create a new-sub channel.  We specify
  138.     that this sub-channel will use the AvatarOutDriverProc.  The
  139.     AvatarOutDriverProc is very different from the AvatarFilter.  The
  140.     AvatarFilter converts Avatar commands into the "Out driver packets"
  141.     used internally within VOUT, and the AvatarOutDriverProc performs
  142.     "Out driver Packets" by generating Avatar commands and sending them
  143.     to a text-stream output device.
  144.  
  145.     In "Part 2" of this example, we attach the Avatar filter to this
  146.     newly created sub-channel.
  147.  
  148.     What we end up with as a result of these actions is a sub-channel
  149.     that converts Avatar commands to output driver packets, and then
  150.     converts the output-driver packets back into Avatar commands.  This
  151.     may seem a little uncessarry, but in fact it is not.  We need
  152.     the intermediate conversion step so that (1) any other filters
  153.     which are added to the sub-channel can "understand" the Avatar commands
  154.     (since they are now converted to Out driver packets, (2) so that
  155.     the Avatar driver (or any other driver we may use) can respond
  156.     appropriately.  For the Avatar driver, an appropriate response is not
  157.     to just send out Avatar commands.  It must also "track" everything it
  158.     does (IE: keep track of the current text color, current cursor
  159.     x/y,etc).  By converting the Avatar commands into Out driver
  160.     packets, the Avatar driver now has a format by which it can understand
  161.     and track the Avatar commands "passing through" it.
  162.  
  163.     How about some simple-english:
  164.  
  165.     Even though this example creates a sub-channel which _generates_
  166.     Avatar commands, we still need the Avatar filter to interpret any
  167.     Avatar commands sent into the sub-channel by applications which
  168.     use VOUT our VCRTu.  Why?  Because although it may not seem like
  169.     it, the easiest way to implement and manage a sub-channel which can
  170.     both interpret and generate Avatar commands is to break the two tasks
  171.     up into seperate modules:  In this case, the AvatarFilter (which
  172.     interprets Avatar commands), and the AvatarOutDriverProc (which generates
  173.     Avatar commands).
  174.  
  175.     For more information on filter, driver, sub-channels, etc., be sure
  176.     to read the VOUTu and VINu chapters.
  177.  
  178. <<AvatarOutDriverProc>>
  179.  
  180.   The Avatar output-driver procedure is a VOUT output driver.  This
  181.   output-driver procedure lets you create a sub-channel which will
  182.   send Avatar commands to a specified device in response to VOUT text
  183.   I/O calls (IE: VOutClrScr, VOutWrite, etc).  By default, the
  184.   Avatar output-driver sends its output to the local, primary Avatar
  185.   device (IE:  DOS' Avatar.SYS or OS/2 VIO).  However, by specifying
  186.   other paramaters when a sub-channel using this driver is created,
  187.   Avatar will send its output to any other device, including a VSER
  188.   based serial port.
  189.  
  190.   <<<And what does all that mean?>>>
  191.  
  192.   The AvatarOutDriverProc responds to VOUTClrScr, VOutClrEol, VOutWrite,
  193.   etc. calls by generating Avatar commands.  These Avatar commands can be
  194.   sent to Avatar.SYS, OS/2 VIO, a serial port, or just about anywhere you
  195.   want by specifying the appropriate parameters on a call to
  196.   VOutSubChannelNew.  This driver is the key part that allows you,
  197.   for example, to use the normal TP CRT API functions (ClrScr, Write,
  198.   etc) over the serial port--because VCRTu's CRT API functions work
  199.   via VOUT, and VOUT can generate Avatar via this driver!
  200.  
  201.   <<<Examples and usage>>>
  202.  
  203.   To create a new-sub channel which uses the AvatarOutDriverProc
  204.   and sends its Avatar output to DOS CON: / Avatar.SYS
  205.  
  206.     { Here  we create a new-sub channel off of the CRT output channel }
  207.     { this new-sub channel will use the Avatar output driver procedure. }
  208.  
  209.     { part 1 }
  210.  
  211.     VOutSubChannelNew( CrtOCH,
  212.                        0,
  213.                        'AvatarOUT',
  214.                        AvatarOutDriverProc,
  215.                        caoDOS,0,0                     );
  216.  
  217.     CrtOCH is the channel handle for VCRTus output-channel.
  218.     As a paramater to VOutSubChannelNew, it tells VOUT which channel
  219.     to create a new sub-channel off of.
  220.  
  221.     The second parameter, 0, is the flags parameter.  VOutSubChanneNew
  222.     currently has no flags.
  223.  
  224.     The third parameter, 'AvatarOUT', is the name by which this
  225.     new sub-channel will be managed.
  226.  
  227.  
  228.     The fourth parameter, AvatarOutDriverProc, is the driver-procedure
  229.     which the new sub-channel will use or be "anchored" by.  In this
  230.     example, we specify AvatarOutDriverProc, which creates a sub-channel
  231.     which will generate Avatar commands in response to calls to
  232.     VOutClrScr, VOutWrite, VOUTGotoXY, etc.
  233.  
  234.     The last three parameters are parameters which are passed to the
  235.     AvatarOutDriverProc.
  236.  
  237.       For the AvatarOutDriverProc, the first of these parameters is a
  238.       value which specifies where the Avatar drivers output stream
  239.       should be sent.  In this example, we specify caoDOS, which tells
  240.       the Avatar driver to send its output to the default Avatar device,
  241.       which in DOS is CON: (or Avatar.SYS) and in OS/2 is the
  242.       VIOWriteTTY function.
  243.  
  244.       When the first of these parameters is caoDOS, the other
  245.       two parameters are not used.
  246.  
  247.  
  248.   To create a new-sub channel which uses the AvatarOutDriverProc
  249.   and sends its Avatar output to a custom stream device.
  250.  
  251.     Procedure MySend( Idata : POINTER; Var St : STRING ); Far;
  252.  
  253.     BEGIN
  254.  
  255.       { write ST to wherever here }
  256.  
  257.  
  258.     END;
  259.  
  260.  
  261.     VOutSubChannelNew( CrtOCH,
  262.                        0,
  263.                        'CustAvatarOUT',
  264.                        AvatarOutDriverProc,
  265.                        caoCustom,
  266.                        Longint(@MySend),
  267.                        0                       );
  268.  
  269.  
  270.     CrtOCH is the channel handle for VCRTus output-channel.
  271.     As a paramater to VOutSubChannelNew, it tells VOUT which channel
  272.     to create a new sub-channel off of.
  273.  
  274.     The second parameter, 0, is the flags parameter.  VOutSubChanneNew
  275.     currently has no flags.
  276.  
  277.     The third parameter, 'CustAvatarOUT', is the name by which this
  278.     new sub-channel will be managed.
  279.  
  280.     The fourth parameter, AvatarOutDriverProc, is the driver-procedure
  281.     which the new sub-channel will use or be "anchored" by.  In this
  282.     example, we specify AvatarOutDriverProc, which creates a sub-channel
  283.     which will generate Avatar commands in response to calls to
  284.     VOutClrScr, VOutWrite, VOUTGotoXY, etc.
  285.  
  286.     The last three parameters are parameters which are passed to the
  287.     AvatarOutDriverProc.
  288.  
  289.       For the AvatarOutDriverProc, the first of these parameters is a
  290.       value which specifies where the Avatar drivers output stream
  291.       should be sent.  In this example, we specify caoCustom, which tells
  292.       the Avatar driver to send its output to a custom send-procedure.
  293.  
  294.       When the first of these parameters is caoCustom, the second
  295.       parameter should be a pointer to the procedure to call when
  296.       AvatarOutDriverProc needs to send out text.  Since this
  297.       parameter is defined as a longint, this procedure-pointer needs
  298.       to be cast to a LONGINT.
  299.  
  300.       When using caoCustom, the third parameter is a 32-bit instance
  301.       data value that will be passed to the custom send-procedure.
  302.       Every time it is called (This is the IData paramater on the
  303.       MySend procedure).  You can use this 32-bit value for whatever
  304.       you'd like.  (IE: as a pointer to other information your
  305.       custom send-procedure might need, etc)
  306.  
  307. For more information on text filters, drivers, sub-channels, etc., be sure
  308. to read the VOUTu and VINu chapters.
  309.  
  310. <Interface>
  311.  
  312. -*)
  313.  
  314.  
  315. Unit VAvtIOu;
  316.  
  317. Interface
  318.  
  319. Uses
  320.  
  321.   VTypesu,
  322. {$IFDEF DEBUG}
  323.   VGenu,
  324.   VDebugu,
  325. {$endif}
  326.   VInlineu,
  327.   VStringu,
  328.   VOutu;
  329.  
  330.  
  331. Procedure AvatarFilter(       ODP            : POutDriverPacket );
  332.  
  333. Procedure AttachAvatarFilter(     Chan       : TChanHandle;
  334.                                   SubChan    : STRING              );
  335.  
  336. Implementation
  337.  
  338.  
  339. (*-
  340.  
  341. [FUNCTION]
  342.  
  343. Procedure AvatarFilter(       ODP            : POutDriverPacket );
  344.  
  345. [PARAMETERS]
  346.  
  347. ODP         Pointer to a VOUT Out-driver request packet
  348.  
  349. [RETURNS]
  350.  
  351. (None)
  352.  
  353. [DESCRIPTION]
  354.  
  355. This procedure is an AVATAR 0+ filter for the Visionix Input/Output
  356. architecture.
  357.  
  358. This procedure will "filter" incoming AVATAR requests and generate
  359. the appropriate Out-Driver-Packets (ODP), and pass the new ODP
  360. packets down the driver stack of the sub-channel this filter
  361. is attached to.
  362.  
  363. This procedure should NOT be called directly.  Instead, use the
  364. VOutFilterAttach function to attach this filter to a previously
  365. created output sub-channel.
  366.  
  367. [SEE-ALSO]
  368.  
  369. (None)
  370.  
  371. [EXAMPLE]
  372.  
  373.   VOutFilterAttach( TheChan,
  374.                     0,
  375.                     'AVT0+filter',
  376.                     'TheSubChan',
  377.                     AvatarFilter,
  378.                     NIL            );
  379.  
  380. -*)
  381.  
  382.  
  383.  
  384.  
  385. Procedure AvatarFilter(       ODP            : POutDriverPacket );
  386.  
  387. Type
  388.  
  389.  
  390.   TCharBuff = Array[1..32768] of CHAR;
  391.   PCharBuff = ^TCharBuff;
  392.  
  393.  
  394.   TAvatarEmu = RECORD
  395.     State      : BYTE;
  396.     Chars      : STRING;
  397.     CharsToGet : BYTE;
  398.     S          : STRING;
  399.   END;
  400.  
  401.   PAvatarEmu = ^TAvatarEmu;
  402.  
  403.   TAvatarFilterIData = Record
  404.  
  405.     Off        : WORD;
  406.     Name       : TProcName;
  407.  
  408.     AvatarEMU  : TAvatarEMU;
  409.  
  410.   END;  { TCRTOutDriverIData }
  411.  
  412.   PAvatarFilterIData = ^TAvatarFilterIData;
  413.  
  414.   {----}
  415.  
  416. Var
  417.   IData      : PAvatarFilterIData;
  418.  
  419.   Z          : INTEGER;
  420.  
  421.   SBuff      : STRING;
  422.  
  423.   testx,testy: INTEGER;
  424.  
  425.   {---------------------------------------------------}
  426.  
  427.   Procedure SBuffFlush;
  428.  
  429.  
  430.   Var
  431.     MyODP : TOutDriverPacket;
  432.  
  433.   BEGIN
  434.  
  435.     If SBuff<>'' Then
  436.     BEGIN
  437.  
  438.       MyODP.Func   := ODF_WriteBlock;
  439.       MyODP.Buff   := @SBuff[1];
  440.       MyODP.Size   := Byte(SBuff[0]);
  441.       MyODP.Start  := 1;
  442.       MyODP.NextDriver := ODP^.NextDriver;
  443.       MyODP.Status := 0;
  444.  
  445.       CallNextDriver( @MyODP );
  446.  
  447.       SBuff := '';
  448.  
  449.     END;
  450.  
  451.   END;
  452.  
  453.   {---------------------------------------------------}
  454.  
  455.   Procedure AvatartoODP(         TheAvatarEMU   : PAvatarEMU;
  456.                                  Ch             : CHAR;
  457.                                  OrigODP        : POutDriverPacket      );
  458.  
  459.   Var
  460.  
  461.     L1 : INTEGER;
  462.     L2 : BYTE;
  463.     L3 : BYTE;
  464.  
  465.     MyODP : TOutDriverPacket;
  466.  
  467.     aTextAttr : BYTE;
  468.  
  469.     {─────────────────────────────────────────────────────}
  470.  
  471.     Procedure MyWrite( CH: CHAR );
  472.  
  473.     BEGIN
  474.  
  475.       StrAddCh( SBuff, CH );
  476.  
  477.       (*
  478.       ODP.Func   := ODF_WriteChar;
  479.       ODP.CH     := CH;
  480.       ODP.Status := 0;
  481.  
  482.       CallNextDriver( @ODP );
  483.       *)
  484.  
  485.     END;
  486.  
  487.     Procedure MyWriteStr( S : STRING );
  488.  
  489.     Var
  490.      Z : INTEGER;
  491.  
  492.     BEGIN
  493.  
  494.       If (Length(Sbuff)+Length(S)) > 255 Then
  495.         SBuffFlush;
  496.  
  497.       StrAddStr( SBuff, S );
  498.  
  499.       (*
  500.       For Z:=1 to Length( S ) Do
  501.         MyWrite( S[Z] );
  502.       *)
  503.  
  504.  
  505.     END;
  506.  
  507.     {─────────────────────────────────────────────────────}
  508.  
  509.     Function MyGetX : INTEGER;
  510.  
  511.     Var
  512.  
  513.       AnOdp : TOutDriverPacket;
  514.  
  515.     BEGIN
  516.  
  517.       AnOdp := MyOdp;
  518.  
  519.       AnODP.Func   := ODF_GetXY;
  520.       AnODP.Status := 0;
  521.       CallNextDriver( @AnODP );
  522.  
  523.       MyGetX := AnODP.X1;
  524.     END;
  525.  
  526.     Function MyGetY : INTEGER;
  527.  
  528.     Var
  529.  
  530.       AnOdp : TOutDriverPacket;
  531.  
  532.     BEGIN
  533.  
  534.       AnOdp := MyOdp;
  535.  
  536.       AnODP.Func   := ODF_GetXY;
  537.       AnODP.Status := 0;
  538.       CallNextDriver( @AnODP );
  539.  
  540.       MyGetY := AnODP.Y1;
  541.     END;
  542.  
  543.   Const
  544.  
  545.     casStream      = 0;
  546.     casRepeatChar  = 1;
  547.     casCtrlV       = 2;
  548.     casSetAttr     = 3;
  549.     casGotoXY      = 4;
  550.     casScrollUp    = 5;
  551.     casScrollDown  = 6;
  552.     casClearArea   = 7;
  553.     casInitArea    = 8;
  554.     casRepeatString1 = 9;
  555.     casRepeatString2 = 10;
  556.     casRepeatstring3 = 11;
  557.  
  558.  
  559.   Var
  560.     Z : INTEGER;
  561.  
  562.   BEGIN
  563.  
  564.     { MyODP := OrigODP^; }
  565.  
  566.     MyODP.NextDriver := OrigODP^.NextDriver;
  567.  
  568.     With TheAvatarEmu^ Do
  569.     BEGIN
  570.  
  571.       If CharsToGet>0 Then
  572.       BEGIN
  573.         StrAddCH( Chars, CH );
  574.         Dec(CharsToGet);
  575.       END;
  576.  
  577.       If CharsToGet=0 Then
  578.       BEGIN
  579.  
  580.         Case State Of
  581.  
  582.           casStream:
  583.           BEGIN
  584.  
  585.             Case CH Of
  586.  
  587.               {#8:tab}
  588.  
  589.               ^L:
  590.               BEGIN
  591.                 SBuffFlush;
  592.  
  593.                 MyODP.Func   := ODF_SetAttr;
  594.                 MyODP.Attr   := 3;
  595.                 MyODP.Status := 0;
  596.                 CallNextDriver( @MyODP );
  597.  
  598.                 MyODP.Func   := ODF_ClrScr;
  599.                 MyODP.Status := 0;
  600.                 CallNextDriver( @MyODP );
  601.               END;
  602.  
  603.               ^Y:
  604.               BEGIN
  605.                 Chars      := '';
  606.                 CharsToGet := 2;
  607.                 State      := casRepeatChar;
  608.               END;
  609.  
  610.               ^V:State := casCtrlV;
  611.  
  612.             ELSE
  613.               MyWrite( CH );
  614.             END; { case ch of }
  615.  
  616.           END; { state of casStart }
  617.  
  618.  
  619.           casCtrlV:
  620.           BEGIN
  621.             Case CH of
  622.               ^A:State:=casSetAttr;
  623.               ^B:
  624.               BEGIN
  625.                 SBuffFlush;
  626.  
  627.                 MyODP.Func   := ODF_GetAttr;
  628.                 MyODP.Status := 0;
  629.                 CallNextDriver( @MyODP );
  630.                 MyODP.Func   := ODF_SetAttr;
  631.                 MyODP.Attr   := MyODP.Attr OR $80;
  632.                 MyODP.Status := 0;
  633.                 CallNextDriver( @MyODP );
  634.                 State := casStream;
  635.               END;
  636.               ^C:
  637.               BEGIN
  638.                 SBuffFlush;
  639.  
  640.                 MyODP.Func   := ODF_CursorUp;
  641.                 MyODP.NuMVal := 1;
  642.                 MyODP.Status := 0;
  643.                 CallNextDriver( @MyODP );
  644.                 State := casStream;
  645.               END;
  646.               ^D:
  647.               BEGIN
  648.                 SBuffFlush;
  649.  
  650.                 MyODP.Func   := ODF_CursorDown;
  651.                 MyODP.NuMVal := 1;
  652.                 MyODP.Status := 0;
  653.                 CallNextDriver( @MyODP );
  654.                 State := casStream;
  655.               END;
  656.               ^E:
  657.               BEGIN
  658.                 SBuffFlush;
  659.  
  660.                 MyODP.Func   := ODF_CursorLeft;
  661.                 MyODP.NuMVal := 1;
  662.                 MyODP.Status := 0;
  663.                 CallNextDriver( @MyODP );
  664.                 State := casStream;
  665.               END;
  666.               ^F:
  667.               BEGIN
  668.                 SBuffFlush;
  669.  
  670.                 MyODP.Func   := ODF_CursorRight;
  671.                 MyODP.NuMVal := 1;
  672.                 MyODP.Status := 0;
  673.                 CallNextDriver( @MyODP );
  674.                 State := casStream;
  675.               END;
  676.               ^G:
  677.               BEGIN
  678.                 SBuffFlush;
  679.  
  680.                 MyODP.Func   := ODF_ClrEOL;
  681.                 MyODP.Status := 0;
  682.                 CallNextDriver( @MyODP );
  683.                 State := casStream;
  684.               END;
  685.               ^H:
  686.               BEGIN
  687.                 Chars      := '';
  688.                 CharsToGet := 2;
  689.                 State      := casGotoXY;
  690.               END;
  691.               ^I:
  692.               BEGIN
  693.                 {insert mode}
  694.                 State := casStream;
  695.               END;
  696.               ^J:
  697.               BEGIN
  698.                 Chars      := '';
  699.                 CharsToGet := 5;
  700.                 State      := casScrollUp;
  701.               END;
  702.               ^K:
  703.               BEGIN
  704.                 Chars      := '';
  705.                 CharsToGet := 5;
  706.                 State      := casScrollDown;
  707.               END;
  708.               ^L:
  709.               BEGIN
  710.                 Chars      := '';
  711.                 CharsToGet := 3;
  712.                 State      := casClearArea;
  713.               END;
  714.               ^M:
  715.               BEGIN
  716.                 Chars      := '';
  717.                 CharsToGet := 4;
  718.                 State      := casInitArea;
  719.               END;
  720.               ^N:
  721.               BEGIN
  722.                 {delete char }
  723.                 state := casStream;
  724.               END;
  725.               ^Y:
  726.               BEGIN
  727.                 State := casRepeatString1;
  728.                 { get the # of chars in the string }
  729.               END;
  730.  
  731.             ELSE
  732.               State := casStream;
  733.             END; { case char after crtl-v of }
  734.  
  735.           END; { casCTRLv }
  736.  
  737.           casSetAttr:
  738.           BEGIN
  739.             SBuffFlush;
  740.  
  741.             MyODP.Func   := ODF_SetAttr;
  742.             MyODP.Attr   := byte( CH );
  743.             MyODP.Status := 0;
  744.             CallNextDriver( @MyODP );
  745.             State := casStream;
  746.           END;
  747.  
  748.           casGotoXY:
  749.           BEGIN
  750.             SBuffFlush;
  751.  
  752.             MyODP.Func   := ODF_GotoXY;
  753.             MyODP.X1     := Byte(chars[2]);
  754.             MyODP.Y1     := Byte(chars[1]);
  755.             MyODP.Status := 0;
  756.             CallNextDriver( @MyODP );
  757.             State := casStream;
  758.           END;
  759.  
  760.           casRepeatChar:
  761.           BEGIN
  762.  
  763.             S := RepeatString( chars[1], Byte(chars[2] ) );
  764.  
  765.             MyWriteStr( S );
  766.  
  767.             State := casStream;
  768.  
  769.           END;
  770.  
  771.           casRepeatString1:
  772.           BEGIN
  773.             Chars      := '';
  774.             CharsToGet := Byte( CH );
  775.             State      := casRepeatString2;
  776.             { get the string to repeat }
  777.           END;
  778.  
  779.           casRepeatString2:
  780.           BEGIN
  781.             State      := casRepeatString3;
  782.             { get the # of times to repeat }
  783.           END;
  784.  
  785.           casRepeatString3:
  786.           BEGIN
  787.             { do the repeat }
  788.             SBuffFlush;
  789.  
  790.             MyODP.Func   := ODF_RepeatBlock;
  791.             MyODP.NumVal := Byte(CH);
  792.             MyODP.Size   := Length( Chars );
  793.             MyODP.Start  := 1;
  794.             MyODP.Buff   := @chars[1];
  795.             MyODP.Status := 0;
  796.             CallNextDriver( @MyODP );
  797.             (*
  798.             For Z:=1 to Byte(CH) Do
  799.               MyWriteStr( Chars );
  800.             *)
  801.             State := casStream;
  802.           END;
  803.  
  804.           casScrollUp:
  805.           BEGIN
  806.             SBuffFlush;
  807.  
  808.             {
  809.             For Z:=2 to 5 Do
  810.               If Byte(Chars[Z])=0 Then Byte(Chars[Z]):=1;
  811.             }
  812.  
  813.             MyODP.Func   := ODF_RegionScrUp;
  814.             MyODP.NumVal := byte(chars[1]);
  815.             MyODP.X1     := byte(chars[3]);
  816.             MyODP.Y1     := byte(chars[2]);
  817.             MyODP.X2     := byte(chars[5]);
  818.             MyODP.Y2     := byte(chars[4]);
  819.  
  820.             {$IFDEF DEBUG}
  821.               DebugWriteLn('Avatar Scroll Up');
  822.  
  823.               DebugWriteLn('  Current X ......... '+IntToStr( MyGetX ) );
  824.               DebugWriteLn('  Current Y ......... '+IntToStr( MyGetY ) );
  825.               DebugWriteLn('  Scroll count ...... '+IntToStr( MyODP.Numval ) );
  826.               DebugWriteLn('  X1 ................ '+IntToStr( MyODP.X1 ) );
  827.               DebugWriteLn('  Y1 ................ '+IntToStr( MyODP.Y1 ) );
  828.               DebugWriteLn('  X2 ................ '+IntToStr( MyODP.X2 ) );
  829.               DebugWriteLn('  Y2 ................ '+IntToStr( MyODP.Y2 ) );
  830.             {$ENDIF}
  831.  
  832. {            If MyODP.Y2=25 Then MyOdp.Y2:=24;}
  833.             MyODP.Status := 0;
  834.             CallNextDriver( @MyODP );
  835.             State := casStream;
  836.           END;
  837.  
  838.           casScrollDown:
  839.           BEGIN
  840.             SBuffFlush;
  841.  
  842.             {
  843.             For Z:=2 to 5 Do
  844.               If Byte(Chars[Z])=0 Then Byte(Chars[Z]):=1;
  845.             }
  846.  
  847.             MyODP.Func   := ODF_RegionScrDown;
  848.             MyODP.NumVal := byte(chars[1]);
  849.             MyODP.X1     := byte(chars[3]);
  850.             MyODP.Y1     := byte(chars[2]);
  851.             MyODP.X2     := byte(chars[5]);
  852.             MyODP.Y2     := byte(chars[4]);
  853.             MyODP.Status := 0;
  854.  
  855.             {$IFDEF DEBUG}
  856.               DebugWriteLn('Avatar Scroll Up');
  857.               DebugWriteLn('  Current X ......... '+IntToStr( MyGetX ) );
  858.               DebugWriteLn('  Current Y ......... '+IntToStr( MyGetY ) );
  859.               DebugWriteLn('  Scroll count ...... '+IntToStr( MyODP.Numval ) );
  860.               DebugWriteLn('  X1 ................ '+IntToStr( MyODP.X1 ) );
  861.               DebugWriteLn('  Y1 ................ '+IntToStr( MyODP.Y1 ) );
  862.               DebugWriteLn('  X2 ................ '+IntToStr( MyODP.X2 ) );
  863.               DebugWriteLn('  Y2 ................ '+IntToStr( MyODP.Y2 ) );
  864.             {$ENDIF}
  865.  
  866.  
  867.             CallNextDriver( @MyODP );
  868.             State := casStream;
  869.           END;
  870.  
  871.           casClearArea:
  872.           BEGIN
  873.             MyODP.Func   := ODF_GetXY;
  874.             MyODP.Status := 0;
  875.             CallNextDriver( @MyODP );
  876.  
  877.             MyODP.Func   := ODF_RegionFill;
  878.             MyODP.Attr   := byte(chars[1]);
  879.             MyODP.Ch     := ' ';
  880.             MyODP.X2     := Pred(MyODP.X1+byte(chars[3]));
  881.             MyODP.Y2     := Pred(MyODP.Y1+byte(chars[2]));
  882.             MyODP.Status := 0;
  883.  
  884.             {$IFDEF DEBUG}
  885.               DebugWriteLn('Avatar Clear Area');
  886.               DebugWriteLn('  Attribute ......... '+IntToHex( MyODP.Attr ) );
  887.               DebugWriteLn('  X1 ................ '+IntToStr( MyODP.X1 ) );
  888.               DebugWriteLn('  Y1 ................ '+IntToStr( MyODP.Y1 ) );
  889.               DebugWriteLn('  X2 ................ '+IntToStr( MyODP.X2 ) );
  890.               DebugWriteLn('  Y2 ................ '+IntToStr( MyODP.Y2 ) );
  891.             {$ENDIF}
  892.  
  893.  
  894.             CallNextDriver( @MyODP );
  895.  
  896.             State := casStream;
  897.           END;
  898.  
  899.           casInitArea:
  900.           BEGIN
  901.             MyODP.Func   := ODF_GetXY;
  902.             MyODP.Status := 0;
  903.             CallNextDriver( @MyODP );
  904.  
  905.             MyODP.Func   := ODF_RegionFill;
  906.             MyODP.Attr   := byte(chars[1]);
  907.             MyODP.CH     := chars[2];
  908.             MyODP.X2     := Pred(MyODP.X1+byte(chars[4]));
  909.             MyODP.Y2     := Pred(MyODP.Y1+byte(chars[3]));
  910.             MyODP.Status := 0;
  911.  
  912.             {$IFDEF DEBUG}
  913.               DebugWriteLn('Avatar Init Area');
  914.               DebugWriteLn('  Attribute ......... '+IntToHex( MyODP.Attr ) );
  915.               DebugWriteLn('  X1 ................ '+IntToStr( MyODP.X1 ) );
  916.               DebugWriteLn('  Y1 ................ '+IntToStr( MyODP.Y1 ) );
  917.               DebugWriteLn('  X2 ................ '+IntToStr( MyODP.X2 ) );
  918.               DebugWriteLn('  Y2 ................ '+IntToStr( MyODP.Y2 ) );
  919.             {$ENDIF}
  920.  
  921.  
  922.             CallNextDriver( @MyODP );
  923.  
  924.  
  925.             State := casStream;
  926.           END;
  927.  
  928.         END; { case state of }
  929.  
  930.       END; { if CharsToGet=0 }
  931.  
  932.     END; { with TheAvatarEmu^ }
  933.  
  934.   END; { Avatar to odp }
  935.  
  936.   {---------------------------------------------------}
  937.  
  938.  
  939.  
  940. BEGIN  { CRTOutDriverProc }
  941.  
  942.   IData := ODP^.ID;
  943.  
  944.   If ODP^.Status = 0 Then
  945.   BEGIN
  946.  
  947.     Case ODP^.Func Of
  948.  
  949.       ODF_DriverNew:
  950.       BEGIN
  951.  
  952.         {-----------------------------}
  953.         { are they telling me to new? }
  954.         {-----------------------------}
  955.  
  956.         IF @ODP^.OutDriverProc = @AvatarFilter Then
  957.         BEGIN
  958.  
  959.           {-------------------------}
  960.           { Get a new Instance Data }
  961.           { master node.            }
  962.           {-------------------------}
  963.  
  964.           New( Idata );
  965.  
  966.           IData^.Off := 0;
  967.  
  968.           IData^.Name := ODP^.Name^;
  969.  
  970.           FillChar( Idata^.AvatarEmu, SizeOf(TAvatarEmu), 0 );
  971.  
  972.           ODP^.Status    := ODS_Install+ODS_Changed;
  973.           ODP^.ID        := IData;
  974.  
  975.         END; { If ODP^.OutDriverProc --> Us }
  976.  
  977.       END; { ODF_DriverNew }
  978.  
  979.       {----}
  980.  
  981.       ODF_DriverOff:
  982.       BEGIN
  983.  
  984.         If ODP^.Name^ = IData^.Name Then
  985.         BEGIN
  986.  
  987.           Inc( Idata^.Off );
  988.  
  989.         END;  { If ODP^.Name^ }
  990.  
  991.       END;  { ODF_DriverOff }
  992.  
  993.       {----}
  994.  
  995.       ODF_DriverOn:
  996.       BEGIN
  997.  
  998.         If ODP^.Name^ = IData^.Name Then
  999.         BEGIN
  1000.  
  1001.           If Idata^.Off <> 0 Then
  1002.             Dec( Idata^.Off );
  1003.  
  1004.         END;  { ODP^.Name^ }
  1005.  
  1006.       END;  { ODF_DriverOn }
  1007.  
  1008.       {----}
  1009.  
  1010.       ODF_DriverDispose:
  1011.       BEGIN
  1012.  
  1013.         If ODP^.Name^ = IData^.Name Then
  1014.         BEGIN
  1015.  
  1016.           {RemoveFromOutDriverStack }
  1017.  
  1018.           Dispose( IData );
  1019.  
  1020.         END;  { If ODP^.Name^ }
  1021.  
  1022.       END;  { ODF_DriverDispose }
  1023.  
  1024.       {----}
  1025.  
  1026.       ODF_WriteChar:
  1027.       BEGIN
  1028.  
  1029.         SBuff := '';
  1030.  
  1031.         AvatartoODP( @IData^.AvatarEmu,
  1032.                      ODP^.CH,
  1033.                      ODP                  );
  1034.  
  1035.         SBuffFlush;
  1036.  
  1037.         {make sure ODP.func hasnt changed to make us }
  1038.          { do another part of the case statement    }
  1039.  
  1040.       END;  { ODF_WriteChar }
  1041.  
  1042.       {----}
  1043.  
  1044.       ODF_WriteBlock:
  1045.       BEGIN
  1046.  
  1047.         SBuff := '';
  1048.  
  1049.         For Z:=ODP^.Start to ODP^.Size Do
  1050.         BEGIN
  1051.  
  1052.           AvatartoODP( @IData^.AvatarEmu,
  1053.                        PCharBuff( ODP^.Buff )^[Z],
  1054.                        ODP                  );
  1055.  
  1056.         END; { For Z }
  1057.  
  1058.         ODP^.Start := ODP^.Size;
  1059.  
  1060.         SBuffFlush;
  1061.  
  1062.       END;  { ODF_WriteBlock }
  1063.  
  1064.       {----}
  1065.  
  1066.     Else { Else Case }
  1067.  
  1068.       CallNextDriver( ODP );
  1069.  
  1070.     END;  { Case ODP^.Func }
  1071.  
  1072.   END; { If ODP^.Status = 0 }
  1073.  
  1074. END;  { AvatarFilter }
  1075.  
  1076.  
  1077. Procedure AttachAvatarFilter(     Chan       : TChanHandle;
  1078.                                   SubChan    : STRING              );
  1079.  
  1080. BEGIN
  1081.  
  1082.   VOutFilterAttach( Chan,
  1083.                     0,
  1084.                     'AVTFILTER',
  1085.                     SubChan,
  1086.                     AvatarFilter,
  1087.                     0,0,0           );
  1088.  
  1089.  
  1090.  
  1091. END;
  1092.  
  1093.  
  1094.  
  1095. BEGIN
  1096.  
  1097. END.
  1098.  
  1099.  
  1100.